import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;

import world.Composite;
import world.Level;
import world.Shaft;
import world.conditions.ConditionAtLeast200Celcius;
import world.edges.Border;
import world.edges.Door;
import world.edges.Wall;
import world.placement.Direction;
import world.placement.Position;
import world.square.NormalTeleport;
import world.square.Rock;
import world.square.Square;
import world.square.Temperature;
import world.square.TemperatureScale;
import exceptions.IllegalPositionException;
import exceptions.IllegalSquarePlacementException;

/**
 * Main class created to demonstrate the class 'square'.
 * 
 * @version  2.0
 * @author   Wim Marynissen, Frederic Mes
 */
public class MainProgram {

	/**
     * Method executed at the start of the application.
	 * @throws IllegalPositionException 
	 * @throws IllegalSquarePlacementException 
     */
    public static void main(String[] args) throws IllegalSquarePlacementException, IllegalPositionException {
//    	partOne();
//    	partTwo();
    	partThree();
    }
    
    public static void partThree() throws IllegalSquarePlacementException, IllegalPositionException{
    	composite1 = new Composite<Square>(10, 10, 10);
		level = new Level<Square>(3, 3);	
		shaft = new Shaft<Square>(Direction.CEILING, 6);
		composite2 = new Composite<Square>(3, 3, 3);
		level2 = new Level<Square>(2, 2);	
		shaft2 = new Shaft<Square>(Direction.NORTH, 2);
		
		levelSquare1 = new Square (Direction.SOUTH);
		levelSquare2 = new Square (Direction.EAST,Direction.WEST);
		levelSquare3 = new Square (new Temperature (new BigDecimal ("3000"), TemperatureScale.CELCIUS), new BigDecimal("30"), Direction.NORTH,Direction.WEST);
		levelSquare4 = new Square (Direction.NORTH,Direction.EAST);
		levelSquare5 = new Square (Direction.WEST,Direction.SOUTH,Direction.EAST);
		levelSquare6 = new Square (Direction.EAST,Direction.SOUTH);
		levelSquare7 = new Square (Direction.EAST);
		levelSquare8Rock = new Rock ();
		
		ArrayList<Square> destinations = new ArrayList<Square>();
		destinations.add(levelSquare1);
		shaftSquare2Teleportation = new NormalTeleport(destinations,Direction.CEILING);

		shaftSquare1 = new Square (Direction.NORTH);

		level2Square1 = new Square (Direction.SOUTH);
		ArrayList<Square> destinations2 = new ArrayList<Square>();
		destinations2.add(shaftSquare1);
		
		level2Square2Teleportation = new NormalTeleport(destinations2,Direction.CEILING);
		shaft2Square1 = new Square (Direction.NORTH);
		shaft2Square2 = new Square (Direction.NORTH);

		
		level.addSquare(levelSquare7, new Position(0, 3, 0));
		level.addSquare(levelSquare1, new Position(1, 3, 0));
		level.addSquare(levelSquare2, new Position(1, 2, 0));
		level.addSquare(levelSquare3, new Position(1, 1, 0));
		level.addSquare(levelSquare4, new Position(2, 1, 0));
		level.addSquare(levelSquare5, new Position(2, 2, 0));
		level.addSquare(levelSquare6, new Position(2, 3, 0));

		level.addSquare(levelSquare8Rock, new Position(1, 0, 0));
		
		shaft.addSquare(shaftSquare1, new Position(0, 0, 1));
		shaft.addSquare(shaftSquare2Teleportation, new Position(0, 0, 0));

		level2.addSquare(level2Square1, new Position(0, 1, 0));
		level2.addSquare(level2Square2Teleportation, new Position(1, 1, 0));
		
		shaft2.addSquare(shaft2Square1, new Position(0, 0, 0));
		shaft2.addSquare(shaft2Square2, new Position(0, 1, 0));
		
		composite1.addSubDungeon(level, new Position (0, 0, 2));
		composite1.addSubDungeon(shaft, new Position(0, 4, 1));
		composite2.addSubDungeon(level2, new Position (0, 0, 0));
		composite2.addSubDungeon(shaft2, new Position(0, 0, 1));
		composite1.addSubDungeon(composite2, new Position (5, 5, 5));

		
		
		//De volle muur op de scheiding
		System.out.println("Muur van levelSquare7: " + levelSquare7.getBorder(Direction.SOUTH).getBorderElement());
		System.out.println("Muur van shaftSquare1: " + shaftSquare1.getBorder(Direction.NORTH).getBorderElement());
		System.out.println();
		
		//Voorbeeld van posities in level en composite
		System.out.println("Positie levelSquare3 in de level: " + level.getSquares().get(levelSquare3));
		System.out.println("Positie levelSquare3 in de composite1: " + composite1.getSquares().get(levelSquare3));		
		System.out.println("Positie shaft2Square2 in shaft2: " + shaft2.getSquares().get(shaft2Square2));
		System.out.println("Positie shaft2Square2 in composite2: " + composite2.getSquares().get(shaft2Square2));
		System.out.println("Positie shaft2Square2 in composite1: " + composite1.getSquares().get(shaft2Square2));
		System.out.println();
		
		//getRootDungeon
		System.out.println("Rootdungeon van level: " +  level.getRootDungeon().toString());
		System.out.println("Rootdungeon van shaft2: " +  shaft2.getRootDungeon().toString());
		System.out.println();
		
		//getLevels & getShafts
		System.out.println("Levels van composite1: " + composite1.getLevels().toString());
		System.out.println("Shafts van composite1: " + composite1.getShafts().toString());
		System.out.println("Levels van composite2: " + composite2.getLevels().toString());
		System.out.println();

		
		//Navigatie
		System.out.println("Binnen een ruimte navigeren: " +composite1.canNavigateTo(levelSquare1, levelSquare5));
		System.out.println("Van teleportvakje naar bestemming: " +composite1.canNavigateTo(shaftSquare2Teleportation, levelSquare1));
		System.out.println("Van vakje in ene ruimte naar een vakje in de andere ruimte: " + composite1.canNavigateTo(shaftSquare1, levelSquare5));
		System.out.println("Van vakje in ene ruimte naar een vakje in de andere ruimte (2 niveaus): " +composite1.canNavigateTo(level2Square1, levelSquare5));
		System.out.println();
		
		//Iterator
		System.out.println(" De Squares in composite1: ");
		Iterator<Square> compositeIterator = composite1.iterator();
		while (compositeIterator.hasNext()){
			System.out.println(" - " + compositeIterator.next().toString());
		}
		System.out.println();
		System.out.println(" De Squares in composite2: ");

		Iterator<Square> composite2Iterator = composite2.iterator();
		while (composite2Iterator.hasNext()){
			System.out.println(" - " + composite2Iterator.next().toString());
		}
		System.out.println();
		
		//Condities
		System.out.println(composite1.getSquaresWithCondition(new ConditionAtLeast200Celcius()).toString());
		System.out.println();

		//Eigenschappen van de rock
		System.out.println("Temperatuur van de rock: " + levelSquare8Rock.getTemperature().getValue().longValue());
		System.out.println("Humidity van de rock: " + levelSquare8Rock.getHumidity().longValue());

    }
	
	private static Composite<Square> composite1;
    private static Level<Square> level;
	private static Shaft<Square> shaft;
	private static Composite<Square> composite2;
	private static Level<Square> level2;
	private static Shaft<Square> shaft2;
	
	private static Square levelSquare7;
	private static Square levelSquare1;
	private static Square levelSquare2;
	private static Square levelSquare3;
	private static Square levelSquare4;
	private static Square levelSquare5;
	private static Square levelSquare6;
	private static Square shaftSquare1;
	private static Rock levelSquare8Rock;
	private static NormalTeleport shaftSquare2Teleportation;

	private static Square level2Square1;
	private static NormalTeleport level2Square2Teleportation;
	private static Square shaft2Square1;
	private static Square shaft2Square2;
	
       	
    
  
    public static void partOne(){
    	Square square1 = new Square (new Temperature(new BigDecimal("20.155"),TemperatureScale.CELCIUS), new BigDecimal ("20"), Direction.NORTH, Direction.EAST, Direction.SOUTH);    	
		Square square2 = new Square(new Temperature(150,TemperatureScale.CELCIUS),new BigDecimal ("59.01"), Direction.EAST,Direction.SOUTH,Direction.WEST);
		
        System.out.println("Vakje 1:");
        square1.printState();System.out.println();
        System.out.println("Vakje 2:");
        square2.printState();
        System.out.println();System.out.println("---------------------------------");System.out.println();
        
        square1.mergeWith(square2, Direction.EAST);
        System.out.println("Na samenvoegen:");System.out.println();
        System.out.println("Vakje 1:");
        square1.printState();System.out.println();
        System.out.println("Vakje 2:");
        square2.printState();
        
        Temperature t1 = new Temperature(new BigDecimal("20"),TemperatureScale.CELCIUS);
       	System.out.println(t1.hashCode());  
       	System.out.println();
    }
  
    public static void partTwo(){
		position000 = new Position (0, 10, 0);
		position100 = new Position (1, 10, 0);
		position010 = new Position (0, 11, 0);
		position110 = new Position (1, 11, 0);
		position020 = new Position (0, 12, 0);
		position120 = new Position (1, 12, 0);
		door = new Door(true);
		
		square000 = new Square( new Temperature(new BigDecimal ("100"), TemperatureScale.CELCIUS), new BigDecimal ("50"), Direction.NORTH);
		square000.addBorders(new Border(new Wall(false), Direction.EAST), new Border(new Wall(false), Direction.WEST));
		square100 = new Square(new Temperature(new BigDecimal ("90"), TemperatureScale.CELCIUS), new BigDecimal ("25"),Direction.NORTH);
		square100.addBorders(new Border(new Wall(false), Direction.SOUTH));

		square010 = new Square(new Temperature(new BigDecimal ("100"), TemperatureScale.CELCIUS), new BigDecimal ("50"),Direction.WEST);
		square010.addBorders(new Border(door, Direction.EAST),new Border(new Wall(false), Direction.SOUTH));

		square110 = new Square(new Temperature(new BigDecimal ("-30"), TemperatureScale.CELCIUS), new BigDecimal ("70"),Direction.EAST);

		square020 = new Square(Direction.EAST);
		square120 = new Square(new Temperature(new BigDecimal ("-30"), TemperatureScale.CELCIUS), new BigDecimal ("50"),Direction.EAST);
		square120.addBorders(new Border(new Wall(false), Direction.WEST));
		
		square000.addObserver(dungeon);
		square010.addObserver(dungeon);
		square100.addObserver(dungeon);
		square110.addObserver(dungeon);
		square020.addObserver(dungeon);
		square120.addObserver(dungeon);
		door.addObserver(dungeon);
		
		try{
			dungeon.addSquare(square000, position000);
			dungeon.addSquare(square100, position100);
			dungeon.addSquare(square010, position010);
			dungeon.addSquare(square110, position110);
			dungeon.addSquare(square020, position020);
			dungeon.addSquare(square120, position120);
		}
		catch(Exception e){
			System.out.println("Could not add that square at that position");
		}
    			
		Door door = (Door) square110.getBorder(Direction.WEST).getBorderElement();
		door.close();
		
		System.out.println("--> De deur is gesloten.");
		System.out.println("Grootte van Ruimte: " + dungeon.sizeOfSpaceWithSquare(square000));
		
		square000.printTempHum();
		System.out.println("");
		door.open();
		System.out.println("--> De deur is open.");
		System.out.println("Grootte van Ruimte: " + dungeon.sizeOfSpaceWithSquare(square000));
		square000.printTempHum();
		System.out.println();
    } 
    private static Level<Square> dungeon = new Level<Square>(20, 20);
    private static Square square000;
	private static Square square010;
	private static Square square100;
	private static Square square110;
	private static Square square120;
	private static Square square020;
	
	private static Position position000;
	private static Position position100;
	private static Position position010;
	private static Position position110;
	private static Position position020;
	private static Position position120;
	private static Door door;
}
